package com.pkk.blny.utils;

import com.pkk.blny.model.domain.Post;
import com.pkk.blny.model.dto.BackupDto;
import com.pkk.blny.model.dto.HaloConst;
import com.pkk.blny.model.dto.Theme;
import com.pkk.blny.model.enums.BlogPropertiesEnum;
import com.pkk.blny.model.enums.CommonParamsEnum;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.StrUtil;
import com.pkk.blny.model.domain.Post;
import com.pkk.blny.model.dto.BackupDto;
import com.pkk.blny.model.dto.HaloConst;
import com.pkk.blny.model.dto.Theme;
import com.pkk.blny.model.enums.BlogPropertiesEnum;
import com.pkk.blny.model.enums.CommonParamsEnum;
import com.sun.syndication.feed.rss.Channel;
import com.sun.syndication.feed.rss.Content;
import com.sun.syndication.feed.rss.Item;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.WireFeedOutput;
import io.github.biezhi.ome.OhMyEmail;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import javax.imageio.ImageIO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;

/**
 * <pre>
 * 常用工具
 * </pre>
 *
 * @author : RYAN0UP
 * @date : 2017/12/22
 */
@Slf4j
public class HaloUtils {

  /**
   * 获取备份文件信息
   *
   * @param dir dir
   * @return List
   */
  public static List<BackupDto> getBackUps(String dir) {
    StrBuilder srcPathStr = new StrBuilder(System.getProperties().getProperty("user.home"));
    srcPathStr.append("/halo/backup/");
    srcPathStr.append(dir);
    File srcPath = new File(srcPathStr.toString());
    File[] files = srcPath.listFiles();
    List<BackupDto> backupDtos = new ArrayList<>();
    BackupDto backupDto = null;
    // 遍历文件
    if (null != files) {
      for (File file : files) {
        if (file.isFile()) {
          if (StrUtil.equals(file.getName(), ".DS_Store")) {
            continue;
          }
          backupDto = new BackupDto();
          backupDto.setFileName(file.getName());
          backupDto.setCreateAt(getCreateTime(file.getAbsolutePath()));
          backupDto.setFileType(FileUtil.getType(file));
          backupDto.setFileSize(parseSize(file.length()));
          backupDto.setBackupType(dir);
          backupDtos.add(backupDto);
        }
      }
    }
    return backupDtos;
  }

  /**
   * 转换文件大小
   *
   * @param size size
   * @return String
   */
  public static String parseSize(long size) {
    if (size < CommonParamsEnum.BYTE.getValue()) {
      return String.valueOf(size) + "B";
    } else {
      size = size / 1024;
    }
    if (size < CommonParamsEnum.BYTE.getValue()) {
      return String.valueOf(size) + "KB";
    } else {
      size = size / 1024;
    }
    if (size < CommonParamsEnum.BYTE.getValue()) {
      size = size * 100;
      return String.valueOf((size / 100)) + "." + String.valueOf((size % 100)) + "MB";
    } else {
      size = size * 100 / 1024;
      return String.valueOf((size / 100)) + "." + String.valueOf((size % 100)) + "GB";
    }
  }

  /**
   * 获取文件创建时间
   *
   * @param srcPath 文件绝对路径
   * @return 时间
   */
  public static Date getCreateTime(String srcPath) {
    Path path = Paths.get(srcPath);
    BasicFileAttributeView basicview = Files.getFileAttributeView(path, BasicFileAttributeView.class,
        LinkOption.NOFOLLOW_LINKS);
    BasicFileAttributes attr;
    try {
      attr = basicview.readAttributes();
      Date createDate = new Date(attr.creationTime().toMillis());
      return createDate;
    } catch (Exception e) {
      e.printStackTrace();
    }
    Calendar cal = Calendar.getInstance();
    cal.set(1970, 0, 1, 0, 0, 0);
    return cal.getTime();
  }

  /**
   * 获取文件长和宽
   *
   * @param file file
   * @return String
   */
  public static String getImageWh(File file) {
    try {
      BufferedImage image = ImageIO.read(new FileInputStream(file));
      return image.getWidth() + "x" + image.getHeight();
    } catch (Exception e) {
      e.printStackTrace();
      return "";
    }
  }

  /**
   * 获取所有主题
   *
   * @return List
   */
  public static List<Theme> getThemes() {
    List<Theme> themes = new ArrayList<>();
    try {
      // 获取项目根路径
      File basePath = new File(ResourceUtils.getURL("classpath:").getPath());
      // 获取主题路径
      File themesPath = new File(basePath.getAbsolutePath(), "templates/themes");
      File[] files = themesPath.listFiles();
      if (null != files) {
        Theme theme = null;
        for (File file : files) {
          if (file.isDirectory()) {
            if (StrUtil.equals("__MACOSX", file.getName())) {
              continue;
            }
            theme = new Theme();
            theme.setThemeName(file.getName());
            File optionsPath = new File(themesPath.getAbsolutePath(),
                file.getName() + "/module/options.ftl");
            if (optionsPath.exists()) {
              theme.setHasOptions(true);
            } else {
              theme.setHasOptions(false);
            }
            File gitPath = new File(themesPath.getAbsolutePath(), file.getName() + "/.git");
            if (gitPath.exists()) {
              theme.setHasUpdate(true);
            } else {
              theme.setHasUpdate(false);
            }
            themes.add(theme);
          }
        }
      }
    } catch (Exception e) {
      log.error("Themes scan failed：{}", e.getMessage());
    }
    return themes;
  }

  /**
   * 获取主题下的模板文件名
   *
   * @param theme theme
   * @return List
   */
  public static List<String> getTplName(String theme) {
    List<String> tpls = new ArrayList<>();
    try {
      // 获取项目根路径
      File basePath = new File(ResourceUtils.getURL("classpath:").getPath());
      // 获取主题路径
      File themesPath = new File(basePath.getAbsolutePath(), "templates/themes/" + theme);
      File modulePath = new File(themesPath.getAbsolutePath(), "module");
      File[] baseFiles = themesPath.listFiles();
      File[] moduleFiles = modulePath.listFiles();
      if (null != moduleFiles) {
        for (File file : moduleFiles) {
          if (file.isFile() && file.getName().endsWith(".ftl")) {
            tpls.add("module/" + file.getName());
          }
        }
      }
      if (null != baseFiles) {
        for (File file : baseFiles) {
          if (file.isFile() && file.getName().endsWith(".ftl")) {
            tpls.add(file.getName());
          }
        }
      }
    } catch (Exception e) {
      log.error("Failed to get theme template: {}", e.getMessage());
    }
    return tpls;
  }

  /**
   * 获取定制模板 格式 page_xxx
   *
   * @return List
   */
  public static List<String> getCustomTpl(String theme) {
    List<String> tpls = new ArrayList<>();
    try {
      File basePath = new File(ResourceUtils.getURL("classpath:").getPath());
      // 获取主题路径
      File themePath = new File(basePath.getAbsolutePath(), "templates/themes/" + theme);
      File[] themeFiles = themePath.listFiles();
      if (null != themeFiles && themeFiles.length > 0) {
        for (File file : themeFiles) {
          String[] split = StrUtil.removeSuffix(file.getName(), ".ftl").split("_");
          if (split.length == 2 && "page".equals(split[0])) {
            tpls.add(StrUtil.removeSuffix(file.getName(), ".ftl"));
          }
        }
      }
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    }
    return tpls;
  }

  /**
   * 导出为文件
   *
   * @param data 内容
   * @param filePath 保存路径
   * @param fileName 文件名
   */
  public static void postToFile(String data, String filePath, String fileName) throws IOException {
    FileWriter fileWriter = null;
    BufferedWriter bufferedWriter = null;
    try {
      File file = new File(filePath);
      if (!file.exists()) {
        file.mkdirs();
      }
      fileWriter = new FileWriter(file.getAbsoluteFile() + "/" + fileName, true);
      bufferedWriter = new BufferedWriter(fileWriter);
      bufferedWriter.write(data);
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (null != bufferedWriter) {
        bufferedWriter.close();
      }
      if (null != fileWriter) {
        fileWriter.close();
      }
    }
  }

  /**
   * 生成rss
   *
   * @param posts posts
   * @return String
   * @throws FeedException FeedException
   */
  public static String getRss(List<Post> posts) throws FeedException {
    Assert.notEmpty(posts, "posts must not be empty");

    Channel channel = new Channel("rss_2.0");
    if (null == HaloConst.OPTIONS.get(BlogPropertiesEnum.BLOG_TITLE.getProp())) {
      channel.setTitle("");
    } else {
      channel.setTitle(HaloConst.OPTIONS.get(BlogPropertiesEnum.BLOG_TITLE.getProp()));
    }
    if (null == HaloConst.OPTIONS.get(BlogPropertiesEnum.BLOG_URL.getProp())) {
      channel.setLink("");
    } else {
      channel.setLink(HaloConst.OPTIONS.get(BlogPropertiesEnum.BLOG_URL.getProp()));
    }
    if (null == HaloConst.OPTIONS.get(BlogPropertiesEnum.SEO_DESC.getProp())) {
      channel.setDescription("");
    } else {
      channel.setDescription(HaloConst.OPTIONS.get(BlogPropertiesEnum.SEO_DESC.getProp()));
    }
    channel.setLanguage("zh-CN");
    List<Item> items = new ArrayList<>();
    for (Post post : posts) {
      Item item = new Item();
      item.setTitle(post.getPostTitle());
      Content content = new Content();
      String value = post.getPostContent();
      char[] xmlChar = value.toCharArray();
      for (int i = 0; i < xmlChar.length; ++i) {
        if (xmlChar[i] > 0xFFFD) {
          xmlChar[i] = ' ';
        } else if (xmlChar[i] < 0x20 && xmlChar[i] != 't' & xmlChar[i] != 'n' & xmlChar[i] != 'r') {
          xmlChar[i] = ' ';
        }
      }
      value = new String(xmlChar);
      content.setValue(value);
      item.setContent(content);
      item.setLink(
          HaloConst.OPTIONS.get(BlogPropertiesEnum.BLOG_URL.getProp()) + "/archives/" + post.getPostUrl());
      item.setPubDate(post.getPostDate());
      items.add(item);
    }
    channel.setItems(items);
    WireFeedOutput out = new WireFeedOutput();
    return out.outputString(channel);
  }

  /**
   * 获取sitemap
   *
   * @param posts posts
   * @return String
   */
  public static String getSiteMap(List<Post> posts) {
    Assert.notEmpty(posts, "post mut not be empty");
    StrBuilder head = new StrBuilder(
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">");
    StrBuilder urlBody = new StrBuilder();
    String urlPath = HaloConst.OPTIONS.get(BlogPropertiesEnum.BLOG_URL.getProp()) + "/archives/";
    for (Post post : posts) {
      urlBody.append("<url><loc>");
      urlBody.append(urlPath);
      urlBody.append(post.getPostUrl());
      urlBody.append("</loc><lastmod>");
      urlBody.append(DateUtil.format(post.getPostDate(), "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"));
      urlBody.append("</lastmod></url>");
    }
    return head.append(urlBody).append("</urlset>").toString();
  }

  /**
   * 配置邮件
   *
   * @param smtpHost smtpHost
   * @param userName 邮件地址
   * @param password password
   */
  public static void configMail(String smtpHost, String userName, String password) {
    Properties properties = OhMyEmail.defaultConfig(false);
    properties.setProperty("mail.smtp.host", smtpHost);
    OhMyEmail.config(properties, userName, password);
  }

  /**
   * 百度主动推送
   *
   * @param blogUrl 博客地址
   * @param token 百度推送token
   * @param urls 文章路径
   * @return String
   */
  public static String baiduPost(String blogUrl, String token, String urls) {
    Assert.hasText(blogUrl, "blog url must not be blank");
    Assert.hasText(token, "token must not be blank");
    Assert.hasText(urls, "urls must not be blank");

    StrBuilder url = new StrBuilder("http://data.zz.baidu.com/urls?site=");
    url.append(blogUrl);
    url.append("&token=");
    url.append(token);

    StrBuilder result = new StrBuilder();
    PrintWriter out = null;
    BufferedReader in = null;
    try {
      // 建立URL之间的连接
      URLConnection conn = new URL(url.toString()).openConnection();
      // 设置通用的请求属性
      conn.setRequestProperty("Host", "data.zz.baidu.com");
      conn.setRequestProperty("User-Agent", "curl/7.12.1");
      conn.setRequestProperty("Content-Length", "83");
      conn.setRequestProperty("Content-Type", "text/plain");

      // 发送POST请求必须设置如下两行
      conn.setDoInput(true);
      conn.setDoOutput(true);

      // 获取conn对应的输出流
      out = new PrintWriter(conn.getOutputStream());
      out.print(urls.trim());
      // 进行输出流的缓冲
      out.flush();
      // 通过BufferedReader输入流来读取Url的响应
      in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
      String line;
      while ((line = in.readLine()) != null) {
        result.append(line);
      }
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      try {
        if (null != out) {
          out.close();
        }
        if (null != in) {
          in.close();
        }
      } catch (IOException ex) {
        ex.printStackTrace();
      }
    }
    return result.toString();
  }

}
